package automata.conversion;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Stack;
import automata.modelo.InicioFin;
import automata.modelo.Transicion;

import automata.modelo.Automata;

public class ConversionERaAFN {
	static Stack<InicioFin> infin;
	static ArrayList<Transicion> tr;
	static String expresion;
	static ArrayList<Character> simbs;
	static HashSet<Integer> stats;
	// String expresion="ab|*a-";
	int inicio, fin;

	public ConversionERaAFN(String expresion) {
		int i;

		this.expresion = expresion; //expresion posfija
		stats = new HashSet<Integer>();  //estados
		simbs = new ArrayList<Character>(); //simbolos
		infin = new Stack<InicioFin>();  // pila de inicios fin
		tr = new ArrayList<Transicion>(); // Lista de trancisiones

		simbs.add('@');
		
		for (i = 0; i < expresion.length(); i++) {
			if (expresion.charAt(i) != '*' && expresion.charAt(i) != '+'
					&& expresion.charAt(i) != '|' && expresion.charAt(i) != '-') {
				agregarSimbolo(expresion.charAt(i));
				if(!simbs.contains(expresion.charAt(i)))
					simbs.add(expresion.charAt(i));

			} else {

				agregarOperador(expresion.charAt(i));
			}

		}
		System.out.println(simbs);
		inicio = infin.lastElement().getInicio();
		fin = infin.lastElement().getFin();

		System.out.println(tr.size());
		for (i = 0; i < tr.size(); i++) {
			System.out.println(i + ") " + tr.get(i).getDesde() + " "
					+ tr.get(i).getSimbolo() + " " + tr.get(i).getHasta());
		}

	}

	public void setExpresionPosfija(String expresion) {

		this.expresion = expresion;

	}

	public static void agregarSimbolo(char charAt) {

		InicioFin a;
		InicioFin b;
		Transicion t;

		if (infin.isEmpty()) {
			a = new InicioFin();
			t = new Transicion();

			a.setInicio(0);
			a.setFin(1);
			stats.add(0);
			stats.add(1);

			t.setDesde(a.getInicio());
			t.setHasta(a.getFin());
			t.setSimbolo(charAt);
			tr.add(t);
			infin.add(a);
		} else {

			a = infin.pop();
			b = new InicioFin();

			b.setInicio(a.getFin() + 1);
			b.setFin(a.getFin() + 2);
			stats.add(b.getInicio());
			stats.add(b.getFin());

			infin.push(a);
			infin.push(b);

			t = new Transicion();
			t.setDesde(b.getInicio());
			t.setSimbolo(charAt);
			t.setHasta(b.getFin());
			tr.add(t);

		}

	}

	public static void agregarOperador(char c) {
		InicioFin a;
		InicioFin b;
		InicioFin d;
		Transicion t;

		switch (c) {

		case '|':

			a = infin.pop();
			b = infin.pop();

			d = new InicioFin();

			d.setInicio(a.getFin() + 1);
			d.setFin(a.getFin() + 2);
			stats.add(d.getInicio());
			stats.add(d.getFin());

			t = new Transicion();
			t.setDesde(d.getInicio());
			t.setHasta(a.getInicio());
			t.setSimbolo('@');
			tr.add(t);

			t = new Transicion();
			t.setDesde(d.getInicio());
			t.setHasta(b.getInicio());
			t.setSimbolo('@');
			tr.add(t);

			t = new Transicion();
			t.setDesde(a.getFin());
			t.setHasta(d.getFin());
			t.setSimbolo('@');
			tr.add(t);

			t = new Transicion();
			t.setDesde(b.getFin());
			t.setHasta(d.getFin());
			t.setSimbolo('@');
			tr.add(t);

			infin.push(d);
			break;

		case '*':
			a = infin.pop();
			d = new InicioFin();

			d.setInicio(a.getFin() + 1);
			d.setFin(a.getFin() + 2);
			stats.add(d.getInicio());
			stats.add(d.getFin());

			t = new Transicion();
			t.setDesde(d.getInicio());
			t.setHasta(d.getFin());
			t.setSimbolo('@');
			tr.add(t);

			t = new Transicion();
			t.setDesde(a.getFin());
			t.setHasta(a.getInicio());
			t.setSimbolo('@');
			tr.add(t);

			t = new Transicion();
			t.setDesde(d.getInicio());
			t.setHasta(a.getInicio());
			t.setSimbolo('@');
			tr.add(t);

			t = new Transicion();
			t.setDesde(a.getFin());
			t.setHasta(d.getFin());
			t.setSimbolo('@');
			tr.add(t);

			infin.push(d);

			break;

		case '+':

			a = infin.pop();
			d = new InicioFin();

			d.setInicio(a.getFin() + 1);
			d.setFin(a.getFin() + 2);
			stats.add(d.getInicio());
			stats.add(d.getFin());

			t = new Transicion();
			t.setDesde(a.getFin());
			t.setHasta(a.getInicio());
			t.setSimbolo('@');
			tr.add(t);

			t = new Transicion();
			t.setDesde(d.getInicio());
			t.setHasta(a.getInicio());
			t.setSimbolo('@');
			tr.add(t);

			t = new Transicion();
			t.setDesde(a.getFin());
			t.setHasta(d.getFin());
			t.setSimbolo('@');
			tr.add(t);

			infin.push(a);
			infin.push(d);

			break;
		case '-':

			a = infin.pop();
			b = infin.pop();

			d = new InicioFin();

			d.setInicio(b.getInicio());
			d.setFin(a.getFin());
			stats.add(d.getInicio());
			stats.add(d.getFin());

			stats.remove(a.getInicio());

			for (int i = 0; i < tr.size(); i++) {
				if (tr.get(i).getDesde() == a.getInicio()) {
					tr.get(i).setDesde(b.getFin());
				}

				if (tr.get(i).getHasta() == a.getInicio()) {
					tr.get(i).setHasta(b.getFin());
				}
			}

			infin.push(d);

			break;

		default:
			break;

		}
	}

	public Automata getAutomataAFD() {
		ArrayList<String> staux = new ArrayList<String>();
		HashSet<String> fins = new HashSet<String>();
		Automata a = new Automata();
		
		a.setSimbolos(simbs); // simbolos
		a.setEstadoInicial(String.valueOf(inicio)); //Inicial
		fins.add(String.valueOf(fin));//final
		a.setEstadosFinales(fins);//agrega final
		a.setTransiciones(tr); // transisicones
		
		for(int temp : stats){
			staux.add(String.valueOf(temp));
		}
		
		a.setEstados(staux); //estados string
		
		return a;

	}
}


